#include <iostream>
#include <string>
#include <vector>
#include <stdlib.h>

//the qt stuff
#include <Qt>
#include <QtCore>
#include <QFile>
#include <QDir>


//the opencv stuff
#include <cv.h>
#include <cvaux.h>
#include <highgui.h>
#include <errno.h>

#include "eigen.h" 
using namespace std;

/**
 * Return back a list of files (should be fixed to work in windows also)
 * @param dir_name : the name of directory to scan
 * @param file_list : the thing to turn back
 * retun : nothing actually it does
 */
int DbOperation::listImages(string dir_name,vector<string> &file_list){
    string  ALLOWED_EXTENTIONS[] ={"jpeg","JPG","jpg","png","bmp","gif","pgm"};

    QDir dir(QString(dir_name.c_str()));
    
    if (!dir.exists()){
        
        qWarning("Cannot find the example directory");
        return -1;
    }
    
    //set the filters
    dir.setFilter(QDir::Files | QDir::Hidden | QDir::NoSymLinks);
    dir.setSorting(QDir::Size | QDir::Reversed);
    
    QFileInfoList list = dir.entryInfoList();

    for (int i = 0; i < list.size(); ++i) {
        
        QFileInfo fileInfo = list.at(i);
        //std::cout << qPrintable(QString("%1").arg(fileInfo.fileName()));
        //std::cout << std::endl;


        // Need some control for extentions
        bool found = false ;
        
        //spltting the stuff from extention
        QString file_ext = fileInfo.fileName();

        //split it from the extention part
       // cout << "The current file is :" << file_ext.toStdString() <<endl;
        if(file_ext.startsWith((QString)"."))
            continue;

        QStringList file_params=file_ext.split(".");

        if(file_params.size()!=2)
            continue;

        //cout << "The length of the parsed is :" << file_params.size() << endl;
        for(int i=0;i<7;i++){
            //cout << "The current extention is :" << file_params.at(1).toStdString()<<"  "<<ALLOWED_EXTENTIONS[i].c_str()<<endl;
            if(strcmp(ALLOWED_EXTENTIONS[i].c_str(),file_params.at(1).toStdString().c_str())==0){
                found = true;
                break;

            }
        }

        if(found == false)
            continue;

        file_list.push_back(file_ext.toStdString());
                    }

    if (file_list.size()==0){
        cout << "no matching pattern file or no files in db" << endl; 
        return (-2);
    }


    return 0;

}

/**
 * Just prints them
 */
int  DbOperation::printImages(string dir_name){

    //define the man to turn back
    vector<string> flist = vector <string>();
    
   if( (this->listImages(dir_name,flist))!=0){
        cout << "Some error in listing "<<endl;
        return -1;
   }
        
    cout << "The file list is :" << endl;

    for(unsigned int i=0; i<flist.size();i++){
        
        ImageOpt *parsed_name = new ImageOpt();
        this->parseImageName(flist[i],parsed_name);
        //collect the garbage 
        delete parsed_name;
        //cout << flist[i] << endl;
    }
    return 0;
}


bool DbOperation::parseImageName(string filename,ImageOpt *parsed_name){

    QString temp_str(filename.c_str());

    //first check if the format is valid actually we may move that part
    //into another function if we wish ??
    //assuming id_name_part.pgm
    QStringList ql = temp_str.split(".");

    if(ql.size()!=2){
        cout << "The file with wrong extention ?" <<endl;
        return false;
    }

    QStringList ql_under = ql.at(0).split("_");

    if(ql_under.size()!=3){
        cout << "The underscores are id_name_part" << endl;
        return false;
    }

    //daha da guzel yapilabilir ama simdilik bole olsun fixleriz...
    parsed_name->id = atoi(ql_under.at(0).toStdString().c_str());
    strcpy(parsed_name->person_name,ql_under.at(1).toStdString().c_str());
    parsed_name->part = atoi(ql_under.at(2).toStdString().c_str());

    //cout << "*******************************************" << endl;
    //cout << "The parsed file is :" << endl;
    //cout << "id : " << (parsed_name->id) << endl;
    //cout << "name : " << (parsed_name->person_name) << endl;
    //cout << "id : " << (parsed_name->part) << endl;

    //all the stuff should be done here 
    return true;
}

/**
 * Moving a file in a platform independent way with qt
 * @param : they are obvious
 * @param type : if 0 copy if 1 move
 * return : if succesful
 */

bool DbOperation::moveFile(char *source_dir,char *dest_dir,char *source_file,char *dest_file,int type){

      //make them qtish
      QString sf_str(source_file);
      QString sd_str(source_dir);
      QString df_str(dest_file);
      QString dd_str(dest_dir);


      //Make the absolute path for destination 
      dd_str.append("/");
      dd_str.append(df_str);

      //The path for destination is :
      //cout << "The destination path is :"<<dd_str.toStdString() << endl; 
      sd_str.append("/");
      sd_str.append(sf_str);
     

      //The files
      QFile df_file;
      df_file.setFileName(dd_str);
      QFile sf_file;
      sf_file.setFileName(sd_str);

     //cout << "The source file is :"<<sd_str.toStdString() << endl;
    
    if(df_file.exists()){
         cout << "The file in the dest already exists :" << df_str.toStdString()<<endl;
         if(!df_file.remove())
            return false;
      }
      
     if (!sf_file.copy(dd_str)){
          cout << "Copying unsuccesfull" << endl;
          return false;
      }

     // if it is a move
     if(type==1)
      sf_file.remove();


      return true;
}

/**
 * That one adds an image to db test one with specified name
 * @param image_name : the file's name (or maybe the absolute path)
 * @param dir_name : the test dirs place
 * @param person_name : the persons name
 *
 * return : true if succesfull
 */


bool DbOperation::addImage(char *image_name,char *dir_name,char *person_name,char* src_dir){

        //firstly take the image list and generate a filename for current
        
        //dont forget to delete it
        ImageOpt *to_add_info=new ImageOpt();
        int num_images;

        //now get the all list from dir
        
         vector<string> flist = vector <string>();
         if( (this->listImages(dir_name,flist))!=0){
             cout << "Some error in listing "<<endl;
            return false;                        
         }

         num_images = flist.size();

         int max_id = 1; //the max id to find it
         //create a QMap object

        QList<ImageOpt*> dblist;
        
        ImageOpt **temp_ops_struct= new ImageOpt*[num_images];

         for(int i=0;i<num_images;i++){
            temp_ops_struct[i] = new ImageOpt();

            if (this->parseImageName(flist[i],temp_ops_struct[i]))
            {
                if ((temp_ops_struct[i]->id)>max_id){
                    max_id = temp_ops_struct[i]->id;

                }

                //make here some stuff for list
                if (strcmp(temp_ops_struct[i]->person_name,person_name)!=0){
                    continue;
                }

                else{
                    dblist.append(temp_ops_struct[i]);
                    
                }
            }


         }

        // firstly the easy part if it is first name in that category:
        if(dblist.count()==0){
            //cout << "The name does not exist so it is a new entry here " << endl;
            to_add_info->id = (max_id+1);
            strcpy(to_add_info->person_name,person_name);
            to_add_info->part = 1;
        }

        // the harder part
        else{
            //cout << "The lis size is " << dblist.count() << endl;
            //cout << "The name is in db we should chose a part for it " << endl;
            int the_max_part = 1; // which image is it ?

            for (int i = 0; i < dblist.count(); i++) {
                //cout << "The real part is :"<<dblist.at(i)->part << "and the maxpart is :"<< the_max_part << endl;

                if ((dblist.at(i)->part) > (the_max_part)){
                    the_max_part = dblist.at(i)->part;
                }
            }

            //Store the result to new filename 
            to_add_info->id = dblist.at(0)->id; // just take one man
            to_add_info->part = (the_max_part+1);
            strcpy((to_add_info->person_name),person_name);
            //cout << "The info is : id :"<< to_add_info->id << "person_name :" << to_add_info->person_name << "part :" << to_add_info->part << endl;

        }

        char real_filename[80];
        sprintf(real_filename,"%d_%s_%d.pgm",to_add_info->id,to_add_info->person_name,to_add_info->part);
        cout << "The file to be copied is :"<<real_filename<<endl;

        if (this->moveFile(src_dir,dir_name,image_name,real_filename,0)==false){ // just copy it 
            //cout << "The copying failed man" << endl;    
            delete to_add_info;
            to_add_info = NULL;

            return false;

            }
        //here just give it free
        delete to_add_info;
        to_add_info = NULL;

        //free the ones you take before
        delete [] temp_ops_struct;
        temp_ops_struct= NULL;

        return true;
}


/*
 * Adding all directory to database, it is needed when someone
 * wants to add the stuff at once
 * @param dir_name : where to store them
 * @param from_dir : from where
 * @param person_name : whose are they 
 *
 * return : true if success
 * */

 bool DbOperation::addAllDir(char* dir_name,char* person_name,char* from_dir){
 
    //firstly get all the images that should be added to database
    vector<string> flist = vector <string>();
        if( (this->listImages(from_dir,flist))!=0){
            cout << "Some error in listing "<<endl;
            return false;
        }

        if(flist.size()==0)
            return false;

       for(int unsigned i=0;i<(flist.size());i++){
    
        char temp[80];
        strcpy(temp,flist[i].c_str());

        if(!(this->addImage (temp,dir_name,person_name,from_dir)))
           cout << "The image couldnt be processed :" << flist[i] << endl;

    }

    //all the stuff completed here
    return true;


 }

bool DbOperation::removeImage(char *image_name, char *dir_name){
      
    
      //some qtish stuff for easiness and relaxing work ;)
      QString df_str(image_name);
      QString dd_str(dir_name);

      //The path for destination is :
      //cout << "The destination path is :"<<dd_str.toStdString() << endl; 
      dd_str.append("/");
      dd_str.append(df_str);
     

      //The files
      QFile df_file;
      df_file.setFileName(dd_str);

     //cout << "The source file is :"<<sd_str.toStdString() << endl;
    
    if(df_file.exists()){
         //cout << "The file to remove is  :" << df_str.toStdString()<<endl;
         if(!df_file.remove()){
             cout << "Error in deleting the file sorry" << endl;
             return false;

         }
     }

    else{
        cout << "The file doesnt exist couldnt delete" << endl;
        return false;
    }
     
    //sucess
    return true;
}

/**
 * Removing all imaes that related to that person
 * @param person_name : the one to remove
 * @param dir_name : the place of images 
 *
 * return true if succesfull
 *
 */

bool DbOperation::removePerson(char* person_name,char* dir_name){
   
    vector<string> flist = vector <string>();
    if( (this->listImages(dir_name,flist))!=0){
        cout << "Some error in listing "<<endl;
        return false;
    }

    int num_images = flist.size();

    if(num_images==0){
        cout << "Nothing to delete here :"<< endl;
        return false;
    }

    
    vector<int> *del_vector=new vector<int>();

    for(int i=0;i<num_images;i++){
    
        ImageOpt *img = new ImageOpt();
        if(this->parseImageName(flist[i],img)){
            
            //if we have it should be deleted
            if(strcmp(img->person_name,person_name)==0){
                del_vector->push_back(i); 

            }
        
        }
        else{
            delete img;
            img=0;
            continue;
        }

        delete img;
        img=0;
        

    }

    if(del_vector->size()==0){
        cout << "No matching person to delete" << endl;
        return false;
    }

    for(unsigned int i=0;i<(del_vector->size());i++){

        char temp[80];
        strcpy(temp,flist[del_vector->at(i)].c_str());
        if(!(this->removeImage(temp,dir_name))){
            cout << "Error in deleting image"<<endl;
        }
    }

    //success
    delete del_vector;

    return true;

}

//*************************************************************************************************************

/**
 * The constructor here
 */
EigenLearn::EigenLearn(){
    
    //initialize all to 0

    this->faceImages=0;
    this->personMat=0;
    this->avgTrainImg=0;
    this->eigenVector=0;
    this->eigenValMatr=0;
    this->projectedTrainMat=0;

}

/**
 * The destructor part here
 * nothing will change but lets try it 
 */

EigenLearn::~EigenLearn(){
    
    // cout << "Releasing all the data we have occupied" <<endl;
    //lets collect some garbage hihii
    if(this->faceImages!=NULL){
        //cout << "Deleting the face image array"<<endl;
        for(int i=0;i<(this->trainFaces);i++)
            cvReleaseImage(&(this->faceImages[i]));
        cvFree(this->faceImages);
    }


    if(this->personMat!=NULL){
        //cout << "The person mat here "<< endl;
        cvReleaseMat(&(this->personMat));
    }
    
    if(this->avgTrainImg!=NULL){
        //cout << "Releaning the avarage image "<<endl;
        cvReleaseImage( &(this->avgTrainImg) );
    }

    if(this->eigenVector!=NULL){
        //cout << "Deleting the eigen image array"<<endl;
        for(int i=0;i<(this->eigens);i++)
            cvReleaseImage(&(this->eigenVector[i]));
        cvFree(this->eigenVector);
    }

    if(this->eigenValMatr!=NULL){
        //cout << "Deleting the eigen val matr here "<< endl;
        cvReleaseMat(&(this->eigenValMatr));
    }
    
     if(this->projectedTrainMat!=NULL){
        //cout << "Deleting the projected train matrix "<< endl;
        cvReleaseMat(&(this->projectedTrainMat));
    }
   
     //cout << "The releasing ends here "<< endl;

}

/**
 * That one loads the files that are in the trainig place 
 * creates the matrixes for the pca computing
 *
 * @param dirname : the directory to have there
 * return : the result if it is ok or not
 */
 bool EigenLearn::loadFaceImgArray(char *dirname){
    
     int nFaces,iFace = 0; // number of faces

     //allocate here dont forget to give it up
     DbOperation *db = new DbOperation();
     vector<string> flist = vector <string>();
     
     if( (db->listImages(dirname,flist))!=0){
            cout << "Some error in listing "<<endl;
            delete db;
            return false;
        }

     //collect the garbage
    
     //get the num of the images to be processed
     nFaces = flist.size();
     //allocate the space for images firstly
     this->faceImages = (IplImage**)cvAlloc(nFaces*(sizeof(IplImage*)));
     this->personMat = cvCreateMat(1,nFaces,CV_32SC1); // Why to need these ones ? we will see later

     //Load the images from the db
     for(iFace=0;iFace<nFaces;iFace++){
        char temp[128];
        strcpy(temp,dirname);
#ifdef unix
        strcat(temp,"/");
#else
      //  strcat(temp,"\");
#endif 
        strcat(temp,flist[iFace].c_str());
        //cout << "To  what we have: "<<temp<<endl;

        faceImages[iFace]=cvLoadImage(temp,CV_LOAD_IMAGE_GRAYSCALE);
        if(!faceImages[iFace]){
            cout << "The image can not be loaded : "<<flist[iFace]<<endl;
            return false;
        }
        //cvNamedWindow("mainWin", CV_WINDOW_AUTOSIZE); 
        //cvMoveWindow("mainWin", 200, 200);
        //cvShowImage("mainWin", faceImages[iFace] );
        //cvWaitKey(0);
        ImageOpt *temp_img_data = new ImageOpt();
        if (!(db->parseImageName(flist[iFace],temp_img_data))){
            cout << "Error with parsing man" << endl;
            return false;
        }
        
        *(this->personMat->data.i+iFace) = temp_img_data->id; // we will need for comparison !
        //release please
        delete temp_img_data;
     }

     //the succes i hope we come here !
     //that part is owned by 2 classes so should be done generic
     this->trainFaces=nFaces;

     //also release the db class you got
     delete db;

     return true;

}

/**
 * The function computes the eigen values and eigent vectors
 * return : true if succesful
 */

bool EigenLearn::doPca(){
    
    int i;
    CvTermCriteria calcLimit;
    CvSize faceImgSize;

    //en cok -1 kadar olurmus 
    this->eigens =  (this->trainFaces)-1;
    
    //Her alinan resmin boyutunun ayni oldugu dusunulecek standart bir
    //boyut yapacaz. Bu kismi face decetiob kismi yapmalidir
    //bu yuzden ilk resmi aliyoz burda ole iste
    faceImgSize.width = this->faceImages[0]->width;
    faceImgSize.height = this->faceImages[0]->height;

    //eigenvectorler icin yer ayiralim :
    this->eigenVector = (IplImage**)cvAlloc(this->eigens*sizeof(IplImage*));

    //eigen fonksyonu icin gerekli yapiyi olusturalim

    for(i=0;i<(this->eigens);i++){
        this->eigenVector[i]= cvCreateImage(faceImgSize,IPL_DEPTH_32F, 1);

    //allocate eigenvalue matrix
    }
    this->eigenValMatr = cvCreateMat(1,this->eigens,CV_32FC1);

    //the avarage image from eigen
    this->avgTrainImg=cvCreateImage(faceImgSize,IPL_DEPTH_32F,1);

    //Bir de bu pca gibi cok hesap gerektiren kisimlar icin ne zaman duracagini sisteme
    //onceden soylemek daha iyimis o yuzden bole bilşi yapiliyomus
    calcLimit = cvTermCriteria( CV_TERMCRIT_ITER, this->eigens, 1);

    //Bu islemi yapan tek bir fonksyon var bilmem hoca kabul eder mi
    //ama bence yapilmisi var ne gerek var bi daha kasmaya
    //bu fonksyon eigenvectorleri eigenvalualari ve avarage resmi bulur

    cvCalcEigenObjects(
            this->trainFaces,
            (void*)this->faceImages,
            (void*)this->eigenVector,
            CV_EIGOBJ_NO_CALLBACK,
            0,
            NULL,
            &calcLimit,
            this->avgTrainImg,
            this->eigenValMatr->data.fl
            );
   // cout << "Controlling if all passed here "<< endl;

    cvNormalize(this->eigenValMatr,this->eigenValMatr, 1, 0, CV_L1, 0);
    
    //little test of what we have done
    //cvNamedWindow("mainWin", CV_WINDOW_AUTOSIZE);
    //cvMoveWindow("mainWin", 200, 200);
    //cvShowImage("mainWin", this->avgTrainImg );
    //cvWaitKey(0);

    return true;

}

bool EigenLearn::learn(char *dirname){
    //firstly load the images that are in the directory we scanning
    int i,ofset;

    if(this->loadFaceImgArray(dirname)==false){
        cout << "Error in loading image set" << endl;
        return false;
    }

    //do the pca computing (eigen stuff things)
   if(this->doPca()==false){
        cout << "Error in pca computing" << endl;
        return false;
    }
   //now we should project the generated ones
   //create a matris to prject all of them into a new one wgich will be faceXeignes
   this->projectedTrainMat=0;
   this->projectedTrainMat= cvCreateMat(this->trainFaces,this->eigens,CV_32SC1);
   ofset = (this->projectedTrainMat->step)/ sizeof(float); // bu oteleme heralde
    //cout << "The ofset is :" << ofset << endl; 
    
   for (i=0; i<(this->trainFaces);i++){
        //projecting into sub space
        cvEigenDecomposite(
                this->faceImages[i],
                this->eigens,
                this->eigenVector,
                0,
                0,
                this->avgTrainImg,
                (this->projectedTrainMat->data.fl+(i*ofset))
                );
        //cout <<"Debug for : " <<(this->projectedTrainMat->data.fl+(i*ofset)) <<endl;
    }

    //that one will be moved to the conf or header file we will see
    char xmlfile[] = "xmleigen";
    
    if(this->storeTrainigSet(xmlfile,dirname)==false)
        return false;

    cout << "Training data projected succesfully can do testing now" << endl;

    return true;
}

/**
 * That one stores all the computed stuff into a xml file into db
 * @param filename : the xml's filename
 * @param dirname : the dirs place to store it
 * return : true if all is succesfull
 */
bool EigenLearn::storeTrainigSet(char *filename,char *dirname){
    
    // That one will write into the xml file
    CvFileStorage * fileStorage;
    int i;
    char temp_str[80];
    //sprintf(temp_str,"%s/%s.xml",dirname,filename);
    strcpy(temp_str,dirname);
    strcat(temp_str,"/");
    strcat(temp_str,filename);
    strcat(temp_str,".xml");

    
    remove(temp_str);
    //cout << "Deleting the previous xml file :..." << endl;
    //sleep(2);

    //return false;
    //open the thing here
    //cout << "The place is :" << temp_str << endl;
    fileStorage = cvOpenFileStorage(temp_str , 0, CV_STORAGE_WRITE );
    
    
    //cout << "debug debug debug" << endl;
    if (!fileStorage)
        return false;


    //cvNamedWindow("result", CV_WINDOW_AUTOSIZE);
    //cvShowImage( "result",this->avgTrainImg);
    //cvWaitKey(10000);

    //begin to write the stuff
    cvWriteInt( fileStorage, "eigens", this->eigens );
    cvWriteInt( fileStorage, "trainFaces",this->trainFaces);
    cvWrite(fileStorage, "personMat", this->personMat, cvAttrList(0,0));
    cvWrite(fileStorage, "eigenValMatr", this->eigenValMatr, cvAttrList(0,0));
    cvWrite(fileStorage, "projectedTrainMat",this->projectedTrainMat, cvAttrList(0,0));
    cvWrite(fileStorage, "avgTrainImg", this->avgTrainImg, cvAttrList(0,0));

    for(i=0; i<(this->eigens); i++){
        char varname[200];
        sprintf( varname, "eigenVect_%d", i );
        cvWrite(fileStorage, varname,this->eigenVector[i], cvAttrList(0,0));

                                                                    }
    // release the file-storage interface
    cvReleaseFileStorage( &fileStorage );
    return true;
}

//********************************************************************************************************************************************

/**
 * That one will be the recognizer for already tested images
 * will project into eigrnspace and compare with current ones 
 *
 * @param test_dir : The test stuff's directory
 * @param learn_dir : The learn stuffs directory
 *
 * return : true if succesfull
 */

bool EigenTest::recognize(char *test_dir,char *learn_dir){
    
    //hardcoded change it later please ...
    char xmlfile[] ="xmleigen";

    //now loaded the data i should load now the test images
    if (!EigenLearn::loadFaceImgArray(test_dir)){
        cout << "Loading the test data problem here" << endl;
        return false;
    }
    //cout << "The test images loaded in memory " << endl;


    //that part should be called secondly
    if (! this->loadTrainigSet(xmlfile,learn_dir)){
        
        cout << "Error in loading the trainig set "<< endl;
        return false;
    }

    //cout << "The trainig set loaded from xml file into memory " << endl;

    //now all the db stuff is loaded and test images loaded
    //that func is for only one test image so no problem should occur
    
    //allocate place for the projeced teste face
    int indexNearest,theNearest,theReal;

    //cout << "Allocating memory for the test face " << endl;
    this->projectedTestFace=(float *)cvAlloc( EigenLearn::eigens*sizeof(float));

    cvEigenDecomposite(
            EigenLearn::faceImages[0],
            EigenTest::eigens,
            EigenLearn::eigenVector,
            0, 0,
            EigenLearn::avgTrainImg,
            this->projectedTestFace);


    //cout << "Projected the new face into the current eigen space "<< endl;

    indexNearest = this->findClosestImage(0);
   
    //cout << "The nearest found "<< endl;
    //that one loaded from test directory getting its id  its index is
    //0 because we have only 1 image that may cause some performance issues
    //but by getting the xml in memory we can process that one 
    //how many times we need so ..
    //Data got from the test image
    
    if(indexNearest!=(-1)){
    theReal    = EigenLearn::personMat->data.i[0];

    //now get the data from the xml file you have computed before
    theNearest = this->pTrainPersonMat->data.i[indexNearest];
    }
    
    //the hacky patch for deallocating the stuff :)
    EigenLearn::trainFaces = 1;

    if (indexNearest==(-1)){
        cout << "no match"<<endl;
        return false;
    }
    
    //cout << "Match found here !!!"<<endl;
    cout <<"match :"<<theNearest <<endl;
    //cout << "The test id is : " << theReal << " And the id from db that matches is : " << theNearest << endl;
    return true;

}

/*
 * That one makes the comparison and returns back the 
 * persons id's index that is seemed to be closests
 * to our test images
 *
 * @param comparison_type : 0 for euclean 1 for mahanalobis
 * return : the index of the closest person
 *
 */
int EigenTest::findClosestImage(int comparison_type){
   
    //double const_trash = 1.8185e+07;
    double const_trash = DBL_MAX;
    double minDistance = const_trash; // the min distance assign a big value for mehalanobis computed
    //debug
    //cout << "The min distance is " << minDistance<<endl;
    int indexTrain,indexEigen,indexNearest = 0;

    for(indexTrain= 0; indexTrain<EigenLearn::trainFaces;indexTrain++){
    // a default value for distance thingi
    double distanceSquare = 0;

    //loop over the real ones
    for(indexEigen = 0; indexEigen < (EigenLearn::eigens);indexEigen++){
        
        // not sure for that one ???
        float distance = this->projectedTestFace[indexEigen] - EigenLearn::projectedTrainMat->data.fl[(indexTrain*EigenLearn::eigens)+indexEigen];
       
    
        //for euclean
        if (comparison_type==0)
            distanceSquare +=distance*distance;
        else
            distanceSquare +=(distance*distance)/EigenLearn::eigenValMatr->data.fl[indexEigen];

    }

    //a little bit weird if not found the 0 will be the one hmm
    //should have a trashhold
    //should change that one !!!
    if (distanceSquare<minDistance){
        minDistance = distanceSquare;
        indexNearest = indexTrain;
    }
    } 

    //cout << "The trash is like : "<<const_trash << endl;
    cout << "The min distance is :" << minDistance << endl;
    
    if (minDistance == const_trash){
        return (int)(-1);
    }
    else{
        return indexNearest; // return the index here
    }
    }

/**
 * Loading the all training set here the eigenvector eigenvalues avg image and etc ...
 * @param xmlfile : the name of the xml set
 * return : true if loading succesfull
 */
bool EigenTest::loadTrainigSet(const char *xmlfile,char *dirname){
    
    CvFileStorage * fileStorage;
    int i;
    char temp[80];

    sprintf(temp,"%s/%s.xml",dirname,xmlfile);
    fileStorage = cvOpenFileStorage( temp, 0, CV_STORAGE_READ );

    if( !fileStorage )
    {
        cout << "The xml file is not opened :" << temp << endl; 
        return false;
    }

    //cout << "The xml file opened to be read" << endl;

    
    //do the reading in the same order as you wrote it 
     //begin to write the stuff

    EigenLearn::eigens = cvReadIntByName(fileStorage, 0, "eigens", 0);
    EigenLearn::trainFaces = cvReadIntByName(fileStorage,0,"trainFaces",0);
    // That one is the real one that others will be compared with a little confusing here
    this->pTrainPersonMat = (CvMat *)cvReadByName(fileStorage, 0, "personMat", 0);
    EigenLearn::eigenValMatr = (CvMat *)cvReadByName(fileStorage, 0, "eigenValMatr", 0);
    EigenLearn::projectedTrainMat = (CvMat *)cvReadByName(fileStorage, 0, "projectedTrainMat", 0);
    EigenLearn::avgTrainImg = (IplImage *)cvReadByName(fileStorage, 0, "avgTrainImg", 0);

    //allocate space for the eigen vectors
    EigenLearn::eigenVector = (IplImage **)cvAlloc((EigenLearn::trainFaces)*sizeof(IplImage *));
    
    for(i=0;i<(EigenLearn::eigens);i++){
    
        char temp[200];
        sprintf( temp, "eigenVect_%d", i );
        EigenLearn::eigenVector[i]= (IplImage *)cvReadByName(fileStorage, 0, temp, 0);
    }


    //release the resource here
    cvReleaseFileStorage( &fileStorage );
    
    //cout << "All the stuff the allocated i hope no leaks occur" << endl;
    
    return true;


}


// the desctructor to free the other stuff

EigenTest::~EigenTest(){

    if (this->projectedTestFace != NULL)
    {
        cvFree(&(this->projectedTestFace));
    }

    if (this->pTrainPersonMat != NULL){
        cvReleaseMat(&(this->pTrainPersonMat));        
    }

    //cout << "Freed the EigenTest Stuff" << endl;
    
}
